<!DOCTYPE HTML>
<html>
<head>
    <title>WebSocket 聊天客户端</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
            margin: 0;
            background-color: #f4f7f9;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            color: #333;
            padding: 10px;
            box-sizing: border-box;
        }

        .chat-container {
            width: 100%;
            max-width: 600px;
            height: 90vh;
            max-height: 700px;
            background-color: #fff;
            border-radius: 10px;
            box-shadow: 0 5px 20px rgba(0, 0, 0, 0.15);
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }

        .connection-area {
            padding: 15px 20px;
            background-color: #f8f9fa;
            border-bottom: 1px solid #e0e0e0;
            display: flex;
            align-items: center;
            gap: 10px;
            flex-wrap: wrap;
            flex-shrink: 0;
        }

        .connection-area label {
            font-size: 0.9em;
            color: #555;
        }

        .connection-area input[type="text"] {
            flex-grow: 1;
            min-width: 120px;
            padding: 8px 12px;
            border: 1px solid #ccc;
            border-radius: 20px;
            font-size: 0.9em;
            outline: none;
            transition: border-color 0.2s, box-shadow 0.2s;
        }
        .connection-area input[type="text"]:focus {
            border-color: #007bff;
            box-shadow: 0 0 0 0.15rem rgba(0,123,255,.2);
        }

        .connection-area button {
            padding: 8px 15px;
            color: white;
            border: none;
            border-radius: 20px;
            cursor: pointer;
            font-size: 0.9em;
            transition: background-color 0.2s ease, opacity 0.2s;
        }
        .connection-area button.connect {
            background-color: #28a745;
        }
        .connection-area button.disconnect {
            background-color: #dc3545;
        }
        .connection-area button:hover {
            opacity: 0.85;
        }
        .connection-area button:disabled {
            background-color: #ccc;
            cursor: not-allowed;
            opacity: 0.7;
        }

        #messagesDisplayArea {
            flex-grow: 1;
            padding: 20px;
            overflow-y: auto;
            background-color: #e9ecef; /* Slightly off-white background for the chat area */
            border-bottom: 1px solid #e0e0e0;
            min-height: 0;
        }

        .message-wrapper {
            display: flex;
            flex-direction: column; /* Sender name will be above bubble */
            margin-bottom: 18px; /* Increased margin for sender name */
        }

        .sender-name-display {
            font-size: 0.8em;
            color: #555; /* Default sender name color */
            margin-bottom: 4px;
            padding: 0 10px; /* Add some padding if names are long */
        }

        .message-wrapper.sent {
            align-items: flex-end;
        }
        .message-wrapper.sent .sender-name-display {
            text-align: right;
            color: #444; /* Slightly darker for sent name if needed */
        }

        .message-wrapper.received {
            align-items: flex-start;
        }
         .message-wrapper.received .sender-name-display {
            text-align: left;
        }


        .message { /* The bubble itself */
            max-width: 80%; /* Max width of the bubble */
            padding: 10px 15px;
            border-radius: 18px; /* General rounding */
            line-height: 1.45;
            word-wrap: break-word;
            font-size: 0.95em;
            position: relative; /* For the tail */
            box-shadow: 0 1px 2px rgba(0,0,0,0.1);
        }
        .message p { /* Remove default margins from p tag inside bubble */
            margin: 0;
        }

        /* Sent message bubble style - right side */
        .message.sent {
            background-color: #95EC69; /* Greenish-blue from image example, can be adjusted */
            /* A more common light blue: #dcf8c6; or #cce5ff; */
            color: #000; /* Black text for better contrast on light green/blue */
            border-radius: 18px 18px 4px 18px; /* Tail on bottom right */
        }
        .message.sent::after { /* The tail for sent messages */
            content: '';
            position: absolute;
            bottom: 0px; /* Align with bottom of bubble */
            right: -8px; /* Position tail outside the bubble to the right */
            width: 0;
            height: 0;
            border-style: solid;
            /* Creates a triangle pointing right-down */
            border-width: 0 0 15px 15px; /* Adjust size of tail here */
            border-color: transparent transparent #95EC69 transparent;
            /* filter: drop-shadow(1px 1px 0.5px rgba(0,0,0,0.05)); */ /* Optional subtle shadow for tail */

        }

        /* Received message bubble style - left side */
        .message.received {
            background-color: #ffffff;
            color: #333;
            border: 1px solid #e0e0e0; /* Subtle border for white bubble */
            border-radius: 18px 18px 18px 4px; /* Tail on bottom left */
        }
         .message.received::after { /* The tail for received messages */
            content: '';
            position: absolute;
            bottom: 0px; /* Align with bottom of bubble */
            left: -8px; /* Position tail outside the bubble to the left */
            width: 0;
            height: 0;
            border-style: solid;
            /* Creates a triangle pointing left-down */
            border-width: 0 15px 15px 0; /* Adjust size of tail here */
            border-color: transparent #ffffff transparent transparent; /* Match bubble bg */
            /* For bordered white bubble, making tail also bordered is complex, so solid color is simpler */
            /* If you have a border, the tail might need to be a separate element or more complex CSS */
        }
        /* Add a border to the tail for received messages if the bubble has a border */
        .message.received::before {
            content: '';
            position: absolute;
            bottom: 0px;
            left: -9px; /* Slightly offset for the border */
            width: 0;
            height: 0;
            border-style: solid;
            border-width: 0 16px 16px 0; /* Slightly larger for border effect */
            border-color: transparent #e0e0e0 transparent transparent; /* Match border color */
            z-index: -1; /* Place behind the main tail */
        }


        /* System, Info, Error messages (keeping them simple and centered) */
        .message-wrapper.system,
        .message-wrapper.info,
        .message-wrapper.error {
            align-items: center; /* Center the wrapper content */
            margin-top: 10px;
            margin-bottom: 20px;
        }
        .message-wrapper.system .sender-name-display, /* Hide sender name for these */
        .message-wrapper.info .sender-name-display,
        .message-wrapper.error .sender-name-display {
            display: none;
        }
        .message.system,
        .message.info,
        .message.error {
            background-color: #f8f9fa;
            color: #6c757d;
            font-style: italic;
            font-size: 0.85em;
            text-align: center;
            padding: 6px 12px;
            border-radius: 10px;
            max-width: 90%;
            box-shadow: none;
        }
        .message.error {
            background-color: #ffebee;
            color: #c62828;
            font-style: normal;
            font-weight: bold;
        }
        .message.info {
            background-color: #e7f3fe;
            color: #0d6efd;
            font-style: normal;
        }

        .input-area {
            display: flex;
            padding: 15px 20px;
            background-color: #f8f9fa;
            border-top: 1px solid #e0e0e0;
            flex-shrink: 0;
        }

        .input-area input[type="text"] {
            flex-grow: 1;
            padding: 12px 18px;
            border: 1px solid #ccc;
            border-radius: 25px;
            margin-right: 10px;
            font-size: 1em;
            outline: none;
            transition: border-color 0.2s, box-shadow 0.2s;
        }
        .input-area input[type="text"]:focus {
            border-color: #007bff;
            box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
        }

        .input-area button {
            padding: 12px 25px;
            background-color: #007bff;
            color: white;
            border: none;
            border-radius: 25px;
            cursor: pointer;
            font-size: 1em;
            transition: background-color 0.2s ease;
        }
        .input-area button:hover {
            background-color: #0056b3;
        }
        .input-area input[type="text"]:disabled,
        .input-area button:disabled {
            background-color: #e9ecef;
            cursor: not-allowed;
            opacity: 0.7;
        }

        @media (max-width: 480px) {
            .connection-area {
                flex-direction: column;
                align-items: stretch;
            }
            .connection-area input[type="text"] {
                margin-bottom: 8px;
            }
            .connection-area .button-group {
                display: flex;
                gap: 10px;
                justify-content: center;
            }
            .input-area {
                padding: 10px 15px;
            }
             .input-area input[type="text"] {
                padding: 10px 15px;
             }
             .input-area button {
                padding: 10px 20px;
             }
        }
    </style>
</head>
<body>
<div class="chat-container">
    <div class="connection-area">
        <label for="serverIp">服务器IP:</label>
        <input type="text" id="serverIp" value="127.0.0.1">
        <div class="button-group">
            <button onclick="connect()" class="connect">连接</button>
            <button onclick="disconnect()" class="disconnect">断开</button>
        </div>
    </div>

    <div id="messagesDisplayArea"></div>

    <div class="input-area">
        <input type="text" id="messageInput" placeholder="输入消息...">
        <button onclick="send()">发送</button>
    </div>
</div>

<script type="text/javascript">
    var ws;
    var messagesDisplayArea = document.getElementById("messagesDisplayArea");
    var messageInput = document.getElementById("messageInput");
    var serverIpInput = document.getElementById("serverIp");

    // --- MODIFIED writeToScreen function ---
    function writeToScreen(messageContent, type = "info", sender = null) {
        const wrapper = document.createElement("div");
        wrapper.className = "message-wrapper " + type; // e.g., message-wrapper sent

        // Create and append sender name DIV if applicable (outside the bubble)
        if (sender && (type === 'sent' || type === 'received')) {
            const senderDisplay = document.createElement("div");
            senderDisplay.className = "sender-name-display"; // General class for sender name
            // Optionally add type to class if specific styling per type is needed:
            // senderDisplay.className = "sender-name-display " + type;
            senderDisplay.textContent = sender;
            wrapper.appendChild(senderDisplay); // Append to wrapper, BEFORE message bubble
        }

        const messageBubble = document.createElement("div");
        messageBubble.className = "message " + type; // e.g., message sent

        const contentP = document.createElement("p");
        contentP.innerHTML = messageContent; // Use innerHTML to preserve your <b><i> tags
        messageBubble.appendChild(contentP);

        wrapper.appendChild(messageBubble); // Append bubble to wrapper
        messagesDisplayArea.appendChild(wrapper);
        messagesDisplayArea.scrollTop = messagesDisplayArea.scrollHeight;
    }
    // --- END OF MODIFIED writeToScreen function ---


    function connect() {
        if (ws && ws.readyState === WebSocket.OPEN) {
            writeToScreen("已经连接。", "info");
            return;
        }

        var serverAddress = serverIpInput.value;
        if (!serverAddress) {
            alert("请输入服务器IP地址。");
            return;
        }

        serverIpInput.disabled = true;
        document.querySelector('.connection-area .connect').disabled = true;
        document.querySelector('.connection-area .disconnect').disabled = false;

        ws = new WebSocket(`ws://${serverAddress}:8888/service`); // Ensure your port and path are correct
        writeToScreen("正在连接服务器...", "info");

        ws.onopen = function() {
            writeToScreen("连接成功！", "info");
            messageInput.disabled = false;
            document.querySelector('.input-area button').disabled = false;
        };

        ws.onmessage = function(evt) {
            try {
                const data = JSON.parse(evt.data);
                if (data.type === 'chat') {
                    writeToScreen(data.text, "received", data.sender);
                } else if (data.type === 'system') {
                    writeToScreen(data.message, "system"); // No sender for system messages
                }
            } catch (e) {
                 writeToScreen(evt.data, "received", "服务器"); // Fallback if not JSON
            }
        };

        ws.onclose = function(evt) {
            writeToScreen(`连接已关闭。代码: ${evt.code}, 原因: ${evt.reason || '无'}`, "info");
            ws = null;
            serverIpInput.disabled = false;
            document.querySelector('.connection-area .connect').disabled = false;
            document.querySelector('.connection-area .disconnect').disabled = true;
            messageInput.disabled = true;
            document.querySelector('.input-area button').disabled = true;
        };

        ws.onerror = function(evt) {
            writeToScreen(`WebSocket 错误: 无法连接或通讯中断`, "error");
            if (ws && ws.readyState !== WebSocket.OPEN) {
                 serverIpInput.disabled = false;
                 document.querySelector('.connection-area .connect').disabled = false;
                 document.querySelector('.connection-area .disconnect').disabled = true;
                 messageInput.disabled = true;
                 document.querySelector('.input-area button').disabled = true;
            }
        };
    }

    function disconnect() {
        if (ws) {
            ws.close();
        } else {
            writeToScreen("当前未连接。", "info");
        }
    }

    function send() {
        if (ws && ws.readyState === WebSocket.OPEN) {
            var messageText = messageInput.value;
            if (messageText.trim() === "") return;

           const messagePayload = {
                type: 'chat',
               text: messageText
            };
            ws.send(JSON.stringify(messagePayload));
            writeToScreen(messageText, "sent", "你"); // "你" is the sender for local echo
            messageInput.value = "";
        } else {
            writeToScreen("未连接到服务器。请先连接。", "error");
        }
    }

    messageInput.addEventListener("keypress", function(event) {
        if (event.key === "Enter") {
            event.preventDefault();
            if (!document.querySelector('.input-area button').disabled) {
                 send();
            }
        }
    });

    function initializeUI() {
        messageInput.disabled = true;
        document.querySelector('.input-area button').disabled = true;
        document.querySelector('.connection-area .disconnect').disabled = true;
    }

    window.onload = initializeUI;

</script>
</body>
</html>